package com.example.blog.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.example.blog.base.CurrentAccount;
import com.example.blog.base.PageRequestDto;
import com.example.blog.common.StatusEnums;
import com.example.blog.entity.Article;
import com.example.blog.entity.Favorites;
import com.example.blog.entity.SysUser;
import com.example.blog.entity.vo.favorites.FavoritesDetailInfoVO;
import com.example.blog.mapper.FavoritesMapper;
import com.example.blog.service.ArticleService;
import com.example.blog.service.FavoritesService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.example.blog.service.SysUserService;
import com.example.blog.util.BeanUtils;
import com.example.blog.util.CurrentUserUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * <p>
 * 收藏表 服务实现类
 * </p>
 *
 * @author wlh
 * @since 2024-01-10
 */
@Service
public class FavoritesServiceImpl extends ServiceImpl<FavoritesMapper, Favorites> implements FavoritesService {


    @Autowired
    @Lazy
    private ArticleService articleService;

    @Autowired
    @Lazy
    private SysUserService sysUserService;

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void add(List<Long> ffIds, Long articleId) {

        Article article = articleService.getByIdNotNull(articleId);
        CurrentAccount user = CurrentUserUtils.currentUser();
        LambdaUpdateWrapper<Favorites> updateWrapper = new LambdaUpdateWrapper<>();
        updateWrapper.eq(Favorites::getArticleId, articleId)
                .eq(Favorites::getCreatedBy, user.getId());

        List<Favorites> list = list(updateWrapper);
        // 存在
        if (!list.isEmpty()) {
            remove(updateWrapper);
            articleService.incrementFavorite(article, -1);
        }

        remove(updateWrapper);
        articleService.incrementFavorite(article, -1);

        List<Favorites> collect = ffIds.stream()
                .map(ffId -> {
                    Favorites favorites = new Favorites();
                    favorites.setFavoritesFoldersId(ffId);
                    favorites.setArticleId(articleId);
                    favorites.setIsRead(StatusEnums.NOT_READ.getValue());
                    favorites.setUserId(article.getCreatedBy());
                    return favorites;
                })
                .collect(Collectors.toList());

        if (!collect.isEmpty()) {
            saveBatch(collect);
            articleService.incrementFavorite(article, 1);
        }
    }

    @Override
    public void del(Long ffId, Long articleId) {

        Article article = articleService.getByIdNotNull(articleId);
        LambdaUpdateWrapper<Favorites> updateWrapper = new LambdaUpdateWrapper<>();

        updateWrapper.eq(Favorites::getFavoritesFoldersId, ffId)
                .eq(Favorites::getArticleId, articleId);

        remove(updateWrapper);
        articleService.incrementFavorite(article, -1);

    }

    @Override
    public List<Favorites> getByFFId(Long ffid) {
        LambdaQueryWrapper<Favorites> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(Favorites::getFavoritesFoldersId, ffid);

        return list(queryWrapper);
    }

    @Override
    public Long getNewCountByUser(Long userId) {
        LambdaQueryWrapper<Favorites> queryWrapper = new LambdaQueryWrapper<>();

        queryWrapper.eq(Favorites::getUserId, userId)
                .eq(Favorites::getIsRead, StatusEnums.NOT_READ.getValue());

        return count(queryWrapper);
    }

    @Override
    public Page<FavoritesDetailInfoVO> pageList(PageRequestDto pageRequestDto) {
        CurrentAccount currentUser = CurrentUserUtils.currentUser();

        Page<Favorites> result = new Page<>(pageRequestDto.getPageCurrent(), pageRequestDto.getPageSize());

        LambdaQueryWrapper<Favorites> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(Favorites::getUserId, currentUser.getId())
                .orderByAsc(Favorites::getIsRead)
                .orderByDesc(Favorites::getCreatedTime);

        page(result, queryWrapper);

        List<Favorites> records = result.getRecords();

        if (records.isEmpty()) {
            return new Page<>();
        }
        Set<Long> uids = new HashSet<>();
        Set<Long> artIds = new HashSet<>();

        records.forEach(favorites -> {
            uids.add(favorites.getCreatedBy());
            artIds.add(favorites.getArticleId());
        });

        Map<Long, Article> articleMap = articleService.listByIds(artIds)
                .stream()
                .collect(Collectors.toMap(Article::getId, Function.identity()));

        Map<Object, SysUser> sysUserMap = sysUserService.listByIds(uids)
                .stream()
                .collect(Collectors.toMap(SysUser::getId, Function.identity()));

        List<FavoritesDetailInfoVO> list = records
                .stream()
                .map(favorites -> {
                    FavoritesDetailInfoVO detailInfoVO = BeanUtils.copyProperties(favorites, FavoritesDetailInfoVO.class);
                    SysUser sysUser = sysUserMap.get(favorites.getCreatedBy());
                    if (sysUser != null) {
                        BeanUtils.copyProperties(sysUser, detailInfoVO, false);
                    }

                    Article article = articleMap.get(favorites.getArticleId());
                    if (article != null) {
                        detailInfoVO.setSummary(article.getSummary());
                        detailInfoVO.setArticleTitle(article.getTitle());
                    }
                    return detailInfoVO;
                })
                .toList();

        Page<FavoritesDetailInfoVO> detailInfoVOPage = new Page<>();
         BeanUtils.copyProperties(result, FavoritesDetailInfoVO.class, "records");
        detailInfoVOPage.setRecords(list);
        return detailInfoVOPage;
    }

    @Override
    public void read() {

        CurrentAccount currentUser = CurrentUserUtils.currentUser();
        LambdaUpdateWrapper<Favorites> updateWrapper = new LambdaUpdateWrapper<>();
        updateWrapper.eq(Favorites::getCreatedBy, currentUser.getId())
                .eq(Favorites::getIsRead, StatusEnums.NOT_READ.getValue())
                .set(Favorites::getIsRead, StatusEnums.READ.getValue());
        update(updateWrapper);
    }

    @Override
    public List<Favorites> getByFFId(List<Long> ffids) {
        if (ffids.isEmpty()) {
            return new ArrayList<>();
        }
        return list(new LambdaQueryWrapper<Favorites>().in(Favorites::getFavoritesFoldersId, ffids));
    }

    @Override
    public Long getByUserAndArticle(Long userId, Long artId) {
        LambdaQueryWrapper<Favorites> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(Favorites::getCreatedBy, userId)
                .eq(Favorites::getArticleId, artId);
        return count(queryWrapper);
    }
}
